<?php
/**
 * 展会工单综合模型
 * @author ljw 20171119
 */
namespace app\common\model;
use app\common\model\BaseModel;
use app\common\controller\Ps;
use think\Cache;
use think\Db;


class ExbtOrderModel extends BaseModel
{
	protected $table = 'kz_exbt_order';
	static protected $time = 0;
	public $canUpdate = false;

	/**
	 * 工单列表[活动管理者场景]
	 *	
	 * @param      array  $prm    查询的身份条件
	 *
	 * @return     array  工单索引数组
	 * 
	 * @author ljw 20171205
	 * @update ljw 20171229
	 */
	public function orderSortOut(array $prm)
	{
		if(empty($prm['exbt_id']))
			Ps::outp('100300','exbt_id不能没有!!',$prm);
		
		if(empty($prm['stand']))
			Ps::outp('100300','stand不能没有!!',$prm);

		$data_prm = [
			'exbt_id' => $prm['exbt_id'],
			'ex_corp_id' => $prm['stand'] !== 'platform' && !empty($prm['corp_id'])? $prm['corp_id'] :'del',
			'step_stand' => $prm['step_stand'] ?? 'del',
			'order_type' => $prm['order_type'] ?? 'del',
			'booth_type' => $prm['booth_type'] ?? 'del',
			'is_completed' => $prm['is_completed'] ?? 0,
			'is_cancel' => $prm['is_cancel'] ?? 0,
			'booth_id' => $prm['booth_id'] ?? 'del',
			$prm['stand'].'_cid' => $prm['stand'] !== 'platform' && !empty($prm[$prm['stand'].'_cid']) ? $prm[$prm['stand'].'_cid'] : 'del',
		];

		$data_prm = delValueCol($data_prm,['del']);
		// p($data_prm);die;
		$res = Db::name('exbt_order')
			->field('id,exbt_id,order_name,ex_corp_id,order_type,booth_id,booth_name,booth_type,step,part_id,part_name,pavl_name,step_stand,step_name,update_time,is_completed,is_cancel')
			->where($data_prm)
			->page((int)($prm['pgn']??1), (int)($prm['pgs']??10))
			->order('update_time asc')
			->select();
		$op = $res ? [
			'list'=> $res			
		] : [];
		$op['dataCount'] = $res&&empty($prm['is_not_first']) ? Db::name('exbt_order')->where($data_prm)->count(0) : 0 ;
		return $op;
	}


	/**
	 * 工单列表[执行者场景,必须有展位id]
	 * 
	 * @param      array  $prm    查询的身份条件
	 *
	 * @return     array  工单索引数组
	 */
	public function orderListByBid(array $prm)
	{
		if(empty($prm['bid'])){
			Ps::outp('100300','bid不能没有');
		}else if(empty($prm['eid'])){
			Ps::outp('100300','eid不能没有');
		}
		//??? 对应用户关系
		//end verification
		$data_prm = [
			'exbt_id'=>$prm['eid'],
			'booth_id'=>$prm['bid'],
		];
		if(isset($prm['completed'])){
			$prm['completed'] = $prm['completed'];
		}
		if(isset($prm['cancel'])){
			$prm['cancel'] = $prm['cancel'];
		}
		// p($data_prm);die;
		$res = Db::name('exbt_order')->field('id,order_name,step_name,ex_corp_name,booth_name,part_name,pavl_name,order_type,step,update_time')
		->where($data_prm)->select();

		return $res ? $res : [];
	}

	/**
	 * 下单[会场搭建,含校验:一个展会只能一次]
	 *
	 * @param      <int>  $eid    			展会id
	 * @param      <int>  $handler_cid		主场方id
	 *
	 * @return     array
	 */
	public function orderMeet( $eid ,$handler_cid=0)
	{
		if(empty($eid)){
			Ps::outp('100300','展会id不能没有');
		}
		$org_inf = ExbtModel::getExbt($eid); //会场搭建 算主办的帐
		if( !$org_inf )
			Ps::outp('200300','展会不存在!!',[$eid]);
		$odr_data = [
			'order_type' => 1,	//工单类型
			//促发者的信息
			'creator_id' => usr()->uid ?? 0,		  //促发者用户id,	
			'ex_corp_id' => $org_inf['organizer_id'], //此任务主导-企业id
			'ex_corp_name' => $org_inf['full_name'],  //此任务主导-企业名
			'exbt_id' => $eid,			//展会id
		];
		//展会的这类单是唯一的
		/*if(Db::name('exbt_order')->where($odr_data)->find()){
			Ps::outp('200300','此展会的此单已存在，不能重复下单');
		}*/
		$odr_data += [ //企业信息
			'organizer_cid' => ExbtModel::getExbtOrganizerByEid($eid)['corp_id'],								//主办方_企业id
			'handler_cid' => $handler_cid ? $handler_cid : ExbtModel::getExbtHandlerByEid($eid)['corp_id'],	//主场方_企业id
		];
		//主单创建
		$res = $this->makeOrder($odr_data);

		if(!$res || empty($res['exbt_id']) ){
			return ['exbt_id' => 0];
		}else{
			return [
				'order_id' => $res['order_id'],
				'exbt_id' => $res['exbt_id'],
				'order_type_name' => $res['order_type_name'],
				'step' => $res['step'],
				'step_name' => $res['step_name'],					
			];
		}

	}

	/**
	 * 下单[展位相关]
	 * @param	$prm	array    工单参数:
	 *		order_type		工单类型
	 *		eid			展会id
	 *		bid				对应的展位id
	 *		ex_corp_id		[可选参]付费企业id , 注意-{
	 *			特展报图类工单必须传搭建商的corp_id,
	 *			会场搭建类工单必须传主办方的corp_id
	 *		}
	 *		organizer_cid	[可选参]主办方_企业id
	 *		handler_cid		[可选参]主场方_企业id
	 *		builder_cid		[可选参]搭建方_企业id
	 *		exhibitor_cid	[可选参]参展方_企业id
	 *	注意： 
	 *		使用前需进行 子单参数 校验
	 * @return     <array> 下单结果
	 * @author ljw 20171205
	 * @update ljw 20171219
	 */
	public function orderMark(array $prm)
	{
		/* \think\Log::record([
			'qwer' => $prm,
			'trace'=>debug_backtrace()
		],'log');*/
		$order_type = $prm['order_type'] ?? 0;		
		// order_type in [1,2,3,10]都是系统工单
		if(!in_array($order_type,[2,3,5,6,7,8,9,10])){
			Ps::outp('100300','工单参数order_type不合规');
		}

		$mustExists = ['order_type','eid','ex_corp_id'];//一切工单必备参

		//2-4的单，必须校验{uid,cid,stand,eid,bid}等关系的存在
		//5-9的单，
		//		有bid时,必须校验 {cid,stand,eid,bid}关系的存在性
		//		没有bid时，只需校验 {cid,stand,eid}关系的存在性
		if(!empty($prm['ex_corp_id'])){
			$a_cid = $prm['ex_corp_id'];
			$ex_corp = CorpModel::getCorp($a_cid);
			$a_corp_name = $ex_corp['full_name'] ?? '';
		}else{
			$a_cid = 0;
			$a_corp_name = '';
		}
		$u = usr();

		//工单参数定义
		$odr_data = [];
		if(in_array($order_type,[2,3,10])){ //自动工单

			$mustExists[] = 'bid';
			foreach($mustExists as $val){
				if( empty($prm[$val]) && $val!='ex_corp_id'){
					Ps::outp('100300',(string)$val.'必须有!!');
				}
			}

			$odr_data = [
				//促发者的信息
				'creator_id' => 0,					//促发人uid				为0
				'ex_corp_id' => $a_cid,				//付费企业id,	???
				'ex_corp_name' => $a_corp_name, //付费企业名	
				'stand' => $prm['stand'] ?? 'platform',			//发起人的企业stand

				'exbt_id' => $prm['eid'],			//展会id
				'booth_id' => $prm['bid'] ?? 0,		//工单服务对应的展位id
			];
		}else{ // 5,6 7 8 服务增值单
			if(in_array($u->stand,['builder','exhibitor'])){ //展位相关方 bid必须有
				$mustExists[] = 'bid';
			}

			foreach($mustExists as $val){
				if( empty($prm[$val]) ){
					Ps::outp('100300',(string)$val.'必须有值.');
				}
			}
			$checkCond = [
				'corp_id' => $u->cid,
				'exbt_stand' => $u->stand,
				'exbt_id' => $prm['eid'],
				'booth_id' => $prm['bid'] ?? 0,
			];

			if( !ExbtCorpStandModel::checkActor($checkCond+[
				'stand' => $u->stand,
			]) ){ //校验关系
				Ps::outp('200300','此用户关系不存在',$checkCond);
			}

			$odr_data = [
				//促发者的信息
				'creator_id' => $u->uid,			//发起人uid		
				'ex_corp_id' => $a_cid? $a_cid :$u->cid,				//付费企业id	
				'ex_corp_name' => $a_corp_name? $a_corp_name : CorpModel::getCorp($u->cid)['full_name'], //付费企业名	

				'exbt_id' => $prm['eid'],			//展会id
				'booth_id' => $prm['bid'],			//工单服务对应的展位id
			];
		}
		$odr_data += [ //企业信息			
			'organizer_cid' => $prm['organizer_cid'] ?? 0,//主办方_企业id
			'handler_cid' => $prm['handler_cid'] ?? 0,//主场方_企业id
			'builder_cid' => $prm['builder_cid'] ?? 0,//搭建方_企业id
			'exhibitor_cid' => $prm['exhibitor_cid'] ?? 0,//参展方_企业id
		];
		//主单创建
		$res = $this->makeOrder($odr_data+[
			'order_type' => $prm['order_type'],	//工单类型码
			'content' => $prm['content'] ?? '',
		]);

		if(!$res || empty($res['exbt_id']) ){
			return ['exbt_id' => 0];
		}else{
			return [
				'order_id' => $res['order_id'],				
				'order_type_name' => $res['order_type_name'],
				'exbt_id' => $res['exbt_id'],
				'step' => $res['step'],
				'step_name' => $res['step_name'],					
			];
		}


	}

	/**
	 * 主单创建
	 *
	 * 注意使用时，请自行使用事务
	 * 
	 * @param	$prm	array    工单参数:
	 *		order_type		工单类型
	 *		exbt_id			展会id
	 *		booth_id		对应的展位id
	 *		
	 *		organizer_cid	[可选参]主办方_企业id
	 *		handler_cid		[可选参]主场方_企业id
	 *		builder_cid		[可选参]搭建方_企业id
	 *		exhibitor_cid	[可选参]参展方_企业id
	 * @return     int string 生成的单号 
	 * @author ljw 20171121
	 * @update ljw 20171203
	 */
	public function makeOrder(array $prm)
	{
		//展位id处理，跟展位无关时(如会场布置工单) 为 0
		if($prm['order_type'] == 1){
			$bid = 0;
		}else{
			$bid = $prm['booth_id'];
		}

		//展区信息
		$bp = $bid ? ExbtModel::getBoothInfoByBid($bid) : [];
		if($bid && !$bp)
			Ps::outp('500900','数据有误!找不到该展会信息',['bid'=>$bid]);

		$step = OrderStepModel::stepInfo($prm['order_type'],1);//首步信息
		if(!$step)
			Ps::outp('500900','数据有误!步骤信息不存在');
		self::$time = time();
		$data = [
			'order_type' => $prm['order_type'],	//工单类型id
			'order_name' => $step['type_name'],	//工单类型名
			'exbt_id' => $prm['exbt_id'],		//展会id

			'organizer_cid' => $prm['organizer_cid'] ?? 0,	//主办方_企业id
			'handler_cid' => $prm['handler_cid'] ?? 0,		//主场方_企业id
			'builder_cid' => $prm['builder_cid'] ?? 0,		//搭建方_企业id
			'exhibitor_cid' => $prm['exhibitor_cid'] ?? 0,	//参展方_企业id

			'creator_id' => $prm['creator_id'] ?? 0,		//发起人uid			系统 为0
			'ex_corp_id' => $prm['ex_corp_id'] ?? 0,		//发起人企业id		系统 为0
			'ex_corp_name' => !empty($prm['ex_corp_id'])? CorpModel::getCorp($prm['ex_corp_id'])['full_name']: '', //发起人企业id		系统 为0

			'booth_id' => $bid ?? 0,					//工单服务对应的展位id
			'booth_type' => $bid ? $bp['type']: -1,		//工单服务对应的展位type
			'content' => $prm['content'] ?? '',			//工单备注内容

			'step' => 1, 									//统一控制的关键点-步骤号
			'step_name' => $step['title'],					//工单首步状态
			'step_stand' => $step['step_stand'] ?? '',		//工单首步企业stand

			'booth_name' => $bp['ex_booth'] ?? '',		//展位名，对应展位id
			'part_id' => $bp['hall_id'] ?? 0,				//展区id
			'part_name' =>  !empty($bp['ex_area']) && !empty($bp['ex_hall'])? $bp['ex_area'].$bp['ex_hall'] :'', //展区名+展厅名
			'pavl_id' => $bp['pavl_id'] ?? 0,				//展馆id
			'pavl_name' => $bp['pavl_name'] ?? '', 			//展馆名
			'region_id' => $bp['region_id'] ?? 0,			//地区id

			'expire_time' => $prm['expire_time'] ?? 0,		//完成期限,对应，0-不限时间，按需求给
			'add_time' => self::$time,
			'update_time' => self::$time,
			'status_image' => $prm['status_image'] ?? '',
		];
		// p($data); die;
		$insert_id = Db::name('exbt_order')->insertGetId($data);
		if($insert_id){
			$res = OrderHandleLogModel::add([
				'order_id' => $insert_id,				// 工单id,
				'usr_id' => $data['creator_id'],		// 操作人uid,[系统操作为0],
				'corp_id' => usr()->cid ?? 0 ,			// 操作人企业id,[系统操作为0],
				'corp_name' => $data['corp_name']??'系统',// 操作人企业名,[系统操作为“系统”],
				'stand' => usr()->stand ?? 0 ,			// 操作人企业stand,[系统操作为空],
				'exbt_id' => $data['exbt_id'],			// 操作de展会id,
				'booth_id' => $data['booth_id'],		// 操作de展位id，与展位无关时为0,
				'status_change' => $data['step_name'],	// 所变更的状态,
				'log_content' => $data['order_name'].'类工单创建',// 日志长内容,
			]);
			if(!$res)
				Ps::outp('500300','系统出错,日志插入失败',[
					'sql_str'=> db()->getLastSql(),
				]);

			return [
				'order_id' => $insert_id ,
				'order_type_name' => $step['type_name'],
				'exbt_id' => $prm['exbt_id'],
				'step' => 1,
				'step_name' => $step['title'],
			];
		}else{
			// trace(['debug_msg'=>'下单失败','debug_backtrace'=>debug_backtrace()],'log');
			return ['exbt_id' => 0];
		}
	}

	/**
	 * 步骤检查
	 *
	 * @param      检查条件
	 *		id			工单id
	 *		stand		【可选参】操作者当前会话中的企业立场
	 * 	
	 * @return     boolean  当前用户是否能操作此步骤
	 * 
	 * @tips	Ps:api开发提示	
	 * @author ljw 20171124
	 * @update ljw 20171213
	 */
	public function checkOrderStep(array $usrCond)
	{
		if(empty($usrCond['id']))
			Ps::outp('100300','参不全,工单id必须有',['id'=>$usrCond['id']]);
		$order_info = Db::name('exbt_order')
		->field('order_type,step_stand,booth_id')
		->where([
			'id' => $usrCond['id'], //工单id
		])->find(); //工单存在性
		if(!$order_info)
			Ps::outp('200300','工单不存在',['id'=>$usrCond['id']]);

		//先检查企业身份是否存在
		if(!ExbtCorpStandModel::checkActor($usrCond))
			Ps::outp('200300','展会企业身份不存在',$usrCond);

		if(empty($usrCond['stand'])){
			Ps::outp('200300','此场景下参不全',['stand']);
		}

		if($usrCond['stand'] === $order_info['step_stand']){ //1 工单当前操作立场要对应用户的企业立场				
			if(empty($usrCond['booth_id'])){
				Ps::outp('200300','此场景下参不全',['booth_id']);
			}
			if($order_info['booth_id']){ //展位id,'exhibitor','builder'才需要对应展位
				if($usrCond['booth_id'] == $order_info['booth_id']){
					$this->canUpdate = true;
				}
			}else{ //其他立场不需要对应展位
				$this->canUpdate = true;
			}
		}

		return $this->canUpdate;
	}





	/**
	 * 工单前进一步
	 * @param      $order_id	工单id	
	 * @param      $ref_reason	返回理由	;流程回走(例如:流程中有审核并且审核被拒绝时用到)
	 * 				
	 * @return     array 操作成功与否
	 * @author ljw 20171119
	 */
	public function orderEvolve($order_id,string $ref_reason = '')
	{
		$order_info = Db::name('exbt_order')
		->field('order_name,order_type,step,exbt_id,booth_id')
		->where([
			'id' => $order_id, //工单id
			'is_completed' => 0,//未交付的单
			'is_cancel' => 0, //正常执行的单
		])->find(); //当前状态信息
		if(!$order_info)
			Ps::outp('200300','该工单不存在/不是正常执行状态');
		//获取最后一步的步骤信息
		$last_step = OrderStepModel::stepInfo($order_info['order_type'],'end');
		//未到最后一步才能更新
		if( $last_step && $order_info['step'] == $last_step['step_num'] ){
			Ps::outp('200300','该工单已交付');
		}

		if($ref_reason){ //流程回退
			$prm['step_name'] = '审核不通过';
			$prm['step'] = ['exp','step-1'];
			$nextStep = OrderStepModel::stepInfo($order_info['order_type'],$order_info['step']-1);
			$prm['step_stand'] = $nextStep['step_stand'];
		}else{
			$prm = [ //更新后状态码[步骤号]
				'step'=> ['exp','step+1']
			];

			if( $order_info['step'] == ( (int)$last_step['step_num'])-1 ){ //若是倒数第二步则更新为已交付的单
				$prm['is_completed'] = 1;
				if($order_info['order_type'] == 3){ //展位搭建完成时,发起的撤场工单
					$booth_info = ExbtModel::getBoothInfoByBid($order_info['booth_id']);
					if(!empty($booth_info['type']) && $booth_info['type'] == 0){// ['type'] == 0 特装展位 						
						$new_odr = [
							'order_type' => 10, //撤场工单 10
							'exbt_id' => $order_info['exbt_id'],
							'booth_id' => $order_info['booth_id'],
							'ex_corp_id' => 0,
						];
						$res = $this->orderMark($new_odr);
						//p($res);die;
						if(empty($res['exbt_id'])){
							Ps::outp('500900','[展位搭建]工单创建失败,系统有误',$res);
						}
					}
				}
			}
			//更新后状态名[步骤名]
			$nextStep = OrderStepModel::stepInfo($order_info['order_type'],$order_info['step']+1);
			$prm['step_name'] = $nextStep['title'];
			$prm['step_stand'] = $nextStep['step_stand'];

		}

		$res = Db::name('exbt_order')->where(['id' => $order_id])->update($prm);//影响行数
		$u = usr();
		if($res){
			$res = OrderHandleLogModel::add([
				'order_id' => $order_id,// 工单id,
				'usr_id' => $u->uid,// 操作人uid,[系统操作为0],
				'corp_id' => $u->cid,// 操作人企业id,[系统操作为0],
				'corp_name' => $u->cid? CorpModel::getCorp($u->cid)['full_name']:'系统',// 操作人企业id,[系统操作为“系统”],
				'stand' => $u->stand,// 操作人企业stand,[系统操作为空],
				'exbt_id' => $order_info['exbt_id'],// 操作de展会id,
				'booth_id' => $order_info['booth_id'],// 操作de展位id，与展位无关时为0,
				'status_change' => $prm['step_name'],// 所变更的状态,
				'log_content' => '此'.$order_info['order_name'].'工单的状态变为:'.$prm['step_name'],
			]);
			if(!$res){
				Ps::outp('500300','系统出错,日志插入失败',[
					'sql_str'=> db()->getLastSql(),
				]);
			}
			return [
				'order_id' => $order_id ,
				'order_type_name' => $order_info['order_name'],
				'exbt_id' => $order_info['exbt_id'],
				'step' => $order_info['step'] + 1,
				'step_name' => $prm['step_name'],
			];
		}else{
			trace(['工单更新失败',$data],'info');
			return [
				'exbt_id' => 0,
			];
		}	
		

	}
	
	/**
	 * 工单更新
	 */
	public function stateUpdate($order_id)
	{

		//判断是否能操作
		
		//工单前进一步
		
		return [];
	}

	/**
	 * 工单进度统计方法
	 * @param int $corp_id
	 * @param int|array $order_type
	 * @param int $step_num
	 * @param int $completed -1无 0未完成 1完成
	 * @param string $exbt_stand
	 * @return int
	 */
	public function orderScheduleCount(int $corp_id, $order_type, int $step_num = -1, int $completed = -1, string $exbt_stand)
	{
		if (is_array($order_type)) {
			$str = implode('_', $order_type);
		} else {
			$str = $order_type;
		}


		$key = 'orderScheduleCount_corp_id'. $corp_id . 'order_type' . $str . 'step_num' . $step_num . 'completed' . $completed .  'exbt_stand' . $exbt_stand;


		$count = Cache::remember($key,function() use ($corp_id, $order_type, $step_num, $completed, $exbt_stand) {

			return Db::name('exbt_order')
				->where('exbt_id', 'IN', function ($query) use ($corp_id, $exbt_stand) {
					$query->name('exbt_corp_stand')->where(['corp_id' => $corp_id, 'exbt_stand' => $exbt_stand])->field('exbt_id');
				})
				->where(function ($query) use ($order_type) {
					if (is_array($order_type)) {
						$query->where('order_type', 'in', $order_type);
					} else {
						$query->where(['order_type' => $order_type]);
					}
				})
				->where(function ($query) use ($step_num) {
					if ($step_num != -1) {
						$query->where(['step' => $step_num]);
					}
				})
				->where(function ($query) use ($completed) {
					if ($completed != -1) {
						$query->where(['is_completed' => $completed]);
					}
				})
				->field(true)
				->count();
		}, '0');//有效期一个小时

		return intval($count);
	}

	/**
	 * 主场方统计装修总进度已经完成的数量
	 * @param int $corp_id 主场方企业ID
	 * @return int
	 */
	public function orderScheduleFinishedCountByHandlerId(int $corp_id)
	{
		return $this->orderScheduleCount($corp_id, [1, 3], 2, -1,'handler');
	}

	/**
	 * 主场方统计装修总进度未完成的数量
	 * @param int $corp_id 主场方企业ID
	 * @return int
	 */
	public function orderScheduleUnfinishedCountByHandlerId(int $corp_id)
	{
		return $this->orderScheduleCount($corp_id, [1, 3], 1,-1, 'handler');
	}


	/**
	 * 主场方统计装修总进度所有的数量
	 * @param int $corp_id 主场方企业ID
	 * @return int
	 */
	public function orderScheduleALLCountByHandlerId(int $corp_id)
	{
		return $this->orderScheduleCount($corp_id, [1, 3], -1, -1, 'handler');
	}


}